# Construirea unui tokenizer, bloc cu bloc[[building-a-tokenizer-block-by-block]]

<CourseFloatingBanner chapter={6}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter6/section8.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter6/section8.ipynb"},
]} />

După cum am văzut în secțiunile anterioare, tokenizarea cuprinde mai multe etape:

- Normalizare (orice curățare a textului care este considerată necesară, cum ar fi eliminarea spațiilor sau a accentelor, normalizarea Unicode etc.)
- Pre-tokenizarea (împărțirea inputului în cuvinte)
- Rularea inputului prin model (utilizarea cuvintelor pre-tokenizate pentru a produce o secvență de tokeni)
- Post-procesare (adăugarea tokenilor speciali ai tokenizerului, generarea attention maskului și a ID-urilor de tip token)

Ca un reminder, iată o altă perspectivă asupra procesului general:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline.svg" alt="The tokenization pipeline.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline-dark.svg" alt="The tokenization pipeline.">
</div>

Biblioteca 🤗 Tokenizers a fost construită pentru a oferi mai multe opțiuni pentru fiecare dintre acești pași, pe care le puteți amesteca și combina împreună. În această secțiune vom vedea cum putem construi un tokenizer de la zero, spre deosebire de antrenarea unui tokenizer nou dintr-unul vechi, așa cum am făcut în [secțiunea 2](/course/chapter6/2). Veți putea apoi să construiți orice fel de tokenizer la care vă puteți gândi!

<Youtube id="MR8tZm5ViWU"/>

Mai exact, biblioteca este construită în jurul unei clase centrale `Tokenizer` cu building grupate în submodule:

- `normalizers` conține toate tipurile posibile de `Normalizer` pe care le puteți folosi (lista completă [aici](https://huggingface.co/docs/tokenizers/api/normalizers)).
- `pre_tokenizers` conține toate tipurile de `PreTokenizer` pe care le poți folosi(lista completă [aici](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)).
- `models` conține diferitele tipuri de `Model` pe care le puteți folosi, precum `BPE`, `WordPiece` și `Unigram` (lista completă [aici](https://huggingface.co/docs/tokenizers/api/models)).
- `trainers` conține toate tipurile diferite de `Trainer` pe care le puteți folosi pentru a vă antrena modelul pe un corpus (unul pentru fiecare tip de model; lista completă [aici](https://huggingface.co/docs/tokenizers/api/trainers)).
- `post_processors` conține diferitele tipuri de `PostProcessor` pe care le puteți utiliza (lista completă [aici](https://huggingface.co/docs/tokenizers/api/post-processors)).
- `decoders` conține diferitele tipuri de `Decoder` pe care le puteți utiliza pentru a decoda rezultatele tokenizării (lista completă [aici](https://huggingface.co/docs/tokenizers/components#decoders)).

Puteți găsi întreaga listă de blocuri [aici](https://huggingface.co/docs/tokenizers/components).

## Obținerea unui corpus[[acquiring-a-corpus]]

Pentru a antrena noul nostru tokenizer, vom utiliza un corpus mic de text (astfel încât exemplele să ruleze rapid). Pașii pentru obținerea corpusului sunt similari cu cei pe care i-am urmat la [începutul acestui capitol](/course/chapter6/2), dar de data aceasta vom utiliza datasetul [WikiText-2](https://huggingface.co/datasets/wikitext):

```python
from datasets import load_dataset

dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train")


def get_training_corpus():
    for i in range(0, len(dataset), 1000):
        yield dataset[i : i + 1000]["text"]
```

Funcția `get_training_corpus()` este un generator care va produce batch-uri de 1 000 de texte, pe care le vom utiliza pentru a antrena tokenizerul.

🤗 Tokenizers pot fi, de asemenea, antrenate direct pe fișiere text. Iată cum putem genera un fișier text care să conțină toate textele/inputurile din WikiText-2 pe care le putem utiliza local:

```python
with open("wikitext-2.txt", "w", encoding="utf-8") as f:
    for i in range(len(dataset)):
        f.write(dataset[i]["text"] + "\n")
```

În continuare vă vom arăta cum să vă construiți propriile tokenizere BERT, GPT-2 și XLNet, bloc cu bloc. Acest lucru ne va oferi un exemplu pentru fiecare dintre cei trei algoritmi principali de tokenizare: WordPiece, BPE și Unigram. Să începem cu BERT!

## Construirea unui tokenizator WordPiece de la zero[[building-a-wordpiece-tokenizer-from-scratch]]

Pentru a construi un tokenizer cu biblioteca 🤗 Tokenizers, începem prin a inițializa un obiect `Tokenizer` cu un `model`, apoi îi setăm atributele `normalizer`, `pre_tokenizer`, `post_processor` și `decoder` la valorile dorite.

Pentru acest exemplu, vom crea un `Tokenizer` cu un model WordPiece:

```python
from tokenizers import (
    decoders,
    models,
    normalizers,
    pre_tokenizers,
    processors,
    trainers,
    Tokenizer,
)

tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]"))
```

Trebuie să specificăm `unk_token` astfel încât modelul să știe ce să returneze atunci când întâlnește caractere necunoscute. Alte argumente pe care le putem seta aici includ `vocab` al modelului nostru (vom antrena modelul, deci nu este nevoie să setăm acest lucru) și `max_input_chars_per_word`, care specifică o lungime maximă pentru fiecare cuvânt (cuvintele mai lungi decât valoarea trecută vor fi divizate).

Primul pas al tokenizării este normalizarea, așa că să începem cu aceasta. Deoarece BERT este utilizat pe scară largă, există un `BertNormalizer` cu opțiunile clasice pe care le putem seta pentru BERT: `lowercase` și `strip_accents`, care se explică de la sine; `clean_text` pentru a elimina toate caracterele de control și a înlocui spațiile repetate cu unul singur; și `handle_chinese_chars`, care plasează spații în jurul caracterelor chinezești. Pentru a replica tokenizerul `bert-base-uncased`, putem seta doar acest normalizator:

```python
tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True)
```

În general, atunci când construiți un nou tokenizer, nu veți avea acces la un normalizator atât de util, deja implementat în biblioteca 🤗 Tokenizers - așa că să vedem cum să creăm manual normalizatorul BERT. Biblioteca oferă un normalizator `Lowercase` și un normalizator `StripAccents` și puteți compune mai multe normalizatoare folosind un `Sequence`:

```python
tokenizer.normalizer = normalizers.Sequence(
    [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()]
)
```

De asemenea, folosim un normalizator Unicode `NFD`, deoarece în caz contrar normalizatorul `StripAccents` nu va recunoaște corect caracterele accentuate și astfel nu le va elimina.

După cum am mai văzut, putem folosi metoda `normalize_str()` a `normalizer` pentru a verifica efectele pe care le are asupra unui text dat:

```python
print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?"))
```

```python out
hello how are u?
```

> [!TIP]
> **Pentru a merge mai departe** Dacă testați cele două versiuni ale normalizatorilor anteriori pe un șir care conține caracterul Unicode `u"\u0085"` veți observa cu siguranță că acești doi normalizatori nu sunt exact echivalenți.
> Pentru a nu complica prea mult versiunea cu `normalizers.Sequence` , nu am inclus înlocuirile Regex pe care `BertNormalizer` le cere atunci când argumentul `clean_text` este setat la `True` - care este comportamentul implicit. Dar nu vă faceți griji: este posibil să obțineți exact aceeași normalizare fără a utiliza utilul `BertNormalizer` prin adăugarea a două `normalizers.Replace` la secvența normalizers.

Urmează etapa de pre-tokenizare. Din nou, există un `BertPreTokenizer` pre-construit pe care îl putem utiliza:

```python
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
```

Sau îl putem construi de la zero:

```python
tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()
```

Rețineți că pre-tokenizatorul `Whitespace` separă spațiul și toate caracterele care nu sunt litere, cifre sau caracterul underscore, deci tehnic separă spațiul și punctuația:

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)),
 ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))]
```

Dacă doriți să separați doar spațiile, ar trebui să utilizați în schimb pre-tokenizerul `WhitespaceSplit`:

```python
pre_tokenizer = pre_tokenizers.WhitespaceSplit()
pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))]
```

Ca și în cazul normalizatorilor, puteți utiliza un `Sequence` pentru a compune mai mulți pre-tokenizeri:

```python
pre_tokenizer = pre_tokenizers.Sequence(
    [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()]
)
pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.")
```

```python out
[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)),
 ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))]
```

Următorul pas în pipelineul de tokenizare este rularea inputurilor prin model. Am specificat deja modelul nostru în inițializare, dar mai trebuie să îl antrenăm, ceea ce va necesita un `WordPieceTrainer`. Principalul lucru de reținut atunci când inițializați un trainer în 🤗 Tokenizers este că trebuie să îi transmiteți toți tokenii speciali pe care intenționați să îi utilizați - în caz contrar, acesta nu le va adăuga la vocabular, deoarece acestea nu se află în corpusul de antrenare:

```python
special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"]
trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens)
```

Pe lângă specificarea `vocab_size` și `special_tokens`, putem seta `min_frequency` (numărul de ori în care un simbol trebuie să apară pentru a fi inclus în vocabular) sau putem schimba `continuing_subword_prefix` (dacă dorim să folosim ceva diferit de `##`).

Pentru a antrena modelul nostru folosind iteratorul pe care l-am definit anterior, trebuie doar să executăm această comandă:

```python
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

De asemenea, putem utiliza fișiere text pentru a ne antrena tokenizerul, care ar arăta astfel (în prealabil, reinițializăm modelul cu un `WordPiece` gol):

```python
tokenizer.model = models.WordPiece(unk_token="[UNK]")
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

În ambele cazuri, putem apoi testa tokenizerul pe un text prin apelarea metodei `encode()`:

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.']
```

`encoding`-ul obținut este un `Encoding`, care conține toate rezultatele necesare ale tokenizerului în diferitele sale atribute: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, și `overflowing`.

Ultimul pas în pipelineul de tokenizare este postprocesarea. Trebuie să adăugăm tokenul `[CLS]` la început și tokenul `[SEP]` la sfârșit (sau după fiecare propoziție, dacă avem o pereche de propoziții). Vom folosi un `TemplateProcessor` pentru aceasta, dar mai întâi trebuie să cunoaștem ID-urile tokenilor `[CLS]` și `[SEP]` din vocabular:

```python
cls_token_id = tokenizer.token_to_id("[CLS]")
sep_token_id = tokenizer.token_to_id("[SEP]")
print(cls_token_id, sep_token_id)
```

```python out
(2, 3)
```

Pentru a scrie templateul pentru `TemplateProcessor`, trebuie să specificăm cum să tratăm o singură propoziție și o pereche de propoziții. Pentru ambele, scriem tokeni speciali pe care dorim să îi folosim; prima (sau singura) propoziție este reprezentată de `$A`, în timp ce a doua propoziție (dacă facem encoding unei perechi) este reprezentată de `$B`. Pentru fiecare dintre acestea (tokeni speciali și propoziții), specificăm și ID-ul tipului de token corespunzător după două puncte.

Modelul clasic BERT este astfel definit după cum urmează:

```python
tokenizer.post_processor = processors.TemplateProcessing(
    single=f"[CLS]:0 $A:0 [SEP]:0",
    pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
    special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)],
)
```

Rețineți că trebuie să transmitem ID-urile tokenilor speciali, astfel încât tokenizerul să le poată converti corect în ID-urile lor.

Odată ce acest lucru este adăugat, revenind la exemplul nostru anterior vom obține:

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]']
```

Și pe o pereche de propoziții, obținem rezultatul corect:

```python
encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.")
print(encoding.tokens)
print(encoding.type_ids)
```

```python out
['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]']
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
```

Aproape am terminat de construit acest tokenizer de la zero - ultimul pas este să includem un decodor:

```python
tokenizer.decoder = decoders.WordPiece(prefix="##")
```

Haideți să-l testăm pe `encoding`-ul nostru anterior:

```python
tokenizer.decode(encoding.ids)
```

```python out
"let's test this tokenizer... on a pair of sentences."
```

Grozav! Putem salva tokenizatorul nostru într-un singur fișier JSON, astfel:

```python
tokenizer.save("tokenizer.json")
```

Apoi putem reîncărca acel fișier într-un obiect `Tokenizer` cu metoda `from_file()`:

```python
new_tokenizer = Tokenizer.from_file("tokenizer.json")
```

Pentru a utiliza acest tokenizer în 🤗 Transformers, trebuie să îl încorporăm în `PreTrainedTokenizerFast`. Putem fie să folosim clasa generică, fie, dacă tokenizerul nostru corespunde unui model existent, să folosim clasa respectivă (aici, `BertTokenizerFast`). Dacă aplicați această lecție pentru a construi un tokenizer nou, va trebui să utilizați prima opțiune.

Pentru a include tokenizatorul într-un `PreTrainedTokenizerFast`, putem fie să transmitem tokenizerul construit ca `tokenizer_object`, fie să transmitem fișierul tokenizerului salvat ca `tokenizer_file`. Cel mai important lucru de reținut este că trebuie să setăm manual toți tokenii speciali, deoarece această clasă nu poate deduce din obiectul `tokenizer` care token este tokenul mască, tokenul `[CLS]`, etc.:

```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively
    unk_token="[UNK]",
    pad_token="[PAD]",
    cls_token="[CLS]",
    sep_token="[SEP]",
    mask_token="[MASK]",
)
```

Dacă utilizați o clasă specifică de tokenizer (cum ar fi `BertTokenizerFast`), va trebui să specificați doar tokenii speciali care sunt diferiți de cei impliciți (aici, niciunul):

```python
from transformers import BertTokenizerFast

wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer)
```

Apoi puteți utiliza acest tokenizer ca orice alt tokenizer 🤗 Transformers. Îl puteți salva cu metoda `save_pretrained()` sau îl puteți încărca în Hub cu metoda `push_to_hub()`.

Acum că am văzut cum să construim un tokenizer WordPiece, hai să facem același lucru pentru un tokenizer BPE. Vom merge un pic mai repede, deoarece cunoașteți toți pașii, și vom evidenția doar diferențele.

## Construirea unui tokenizer BPE de la zero[[building-a-bpe-tokenizer-from-scratch]]

Să construim acum un tokenizer GPT-2. Ca și pentru tokenizer BERT, începem prin inițializarea unui `Tokenizer` cu un model BPE:

```python
tokenizer = Tokenizer(models.BPE())
```

De asemenea, la fel ca în cazul BERT, am putea inițializa acest model cu un vocabular, dacă am avea unul (în acest caz, ar trebui să oferim `vocab` și `merges`), dar din moment ce vom antrena de la zero, nu avem nevoie să facem acest lucru. De asemenea, nu trebuie să specificăm un `unk_token` deoarece GPT-2 utilizează BPE la nivel de bytes, care nu necesită acest lucru.

GPT-2 nu utilizează un normalizator, deci sărim peste acest pas și trecem direct la pre-tokenizare:

```python
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
```

Opțiunea pe care am adăugat-o aici la `ByteLevel` nu este pentru a adăuga un spațiu unei propoziții (care este implicit în caz contrar). Putem arunca o privire la pre-tokenizarea unui text exemplu ca înainte:

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!")
```

```python out
[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)),
 ('tokenization', (15, 27)), ('!', (27, 28))]
```

Urmează modelul, care are nevoie de antrenare. Pentru GPT-2, singurul token special este tokenul de sfârșit de text:

```python
trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"])
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

Ca și în cazul `WordPieceTrainer`, precum și `vocab_size` și `special_tokens`, putem specifica `min_frequency` dacă dorim, sau dacă avem un sufix de sfârșit de cuvânt (cum ar fi `</w>`), îl putem seta cu `end_of_word_suffix`.

Acest tokenizer poate fi antrenat și pe fișiere text:

```python
tokenizer.model = models.BPE()
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

Să aruncăm o privire la tokenizarea unui exemplu de text:

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.']
```

Aplicăm postprocesarea la nivel de bytes pentru tokenizerul GPT-2 după cum urmează:

```python
tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
```

Opțiunea `trim_offsets = False` indică post-procesorului că ar trebui să lăsăm offseturile tokenilor care încep cu "Ġ" așa cum sunt: în acest fel, începutul offseturilor va indica spațiul dinaintea cuvântului, nu primul caracter al cuvântului (deoarece spațiul face parte din punct de vedere tehnic din token). Să aruncăm o privire asupra rezultatului cu textul pe căruia tocmai i-am făcut encoding, unde `'Ġtest'` este tokenul de la indexul 4:

```python
sentence = "Let's test this tokenizer."
encoding = tokenizer.encode(sentence)
start, end = encoding.offsets[4]
sentence[start:end]
```

```python out
' test'
```

În cele din urmă, adăugăm un decoder la nivel de bytes:

```python
tokenizer.decoder = decoders.ByteLevel()
```

și putem verifica de două ori dacă funcționează corect:

```python
tokenizer.decode(encoding.ids)
```

```python out
"Let's test this tokenizer."
```

Grozav! Acum că am terminat, putem salva tokenizatorul ca înainte și îl putem încorpora într-un `PreTrainedTokenizerFast` sau `GPT2TokenizerFast` dacă dorim să îl folosim în 🤗 Transformers:

```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    bos_token="<|endoftext|>",
    eos_token="<|endoftext|>",
)
```

or:

```python
from transformers import GPT2TokenizerFast

wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer)
```

Ca un ultim exemplu, vă vom arăta cum să construiți un tokenizer Unigram de la zero.

## Construirea unui tokenizer Unigram de la zero[[building-a-unigram-tokenizer-from-scratch]]

Să construim acum un tokenizer XLNet. Ca și în cazul tokenizerelor anterioare, începem prin inițializarea unui `Tokenizer` cu un model Unigram:

```python
tokenizer = Tokenizer(models.Unigram())
```

Din nou, am putea inițializa acest model cu un vocabular, dacă am avea unul.

Pentru normalizare, XLNet utilizează câteva înlocuiri (care provin din SentencePiece):

```python
from tokenizers import Regex

tokenizer.normalizer = normalizers.Sequence(
    [
        normalizers.Replace("``", '"'),
        normalizers.Replace("''", '"'),
        normalizers.NFKD(),
        normalizers.StripAccents(),
        normalizers.Replace(Regex(" {2,}"), " "),
    ]
)
```

Acest lucru înlocuitește <code>``</code> și <code>''</code> cu <code>"</code> și orice secvență de două sau mai multe spații cu un singur spațiu, precum și ștergerea accentelor în textele ce trebuie tokenizate.

Pre-tokenizerul care trebuie utilizat pentru orice tokenizer SentencePiece este `Metaspace`:

```python
tokenizer.pre_tokenizer = pre_tokenizers.Metaspace()
```

Putem arunca o privire la pre-tokenizarea unui exemplu de text ca mai înainte:

```python
tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!")
```

```python out
[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))]
```

Urmează modelul, care are nevoie de antrenare. XLNet are destul de mulți tokeni speciali:

```python
special_tokens = ["<cls>", "<sep>", "<unk>", "<pad>", "<mask>", "<s>", "</s>"]
trainer = trainers.UnigramTrainer(
    vocab_size=25000, special_tokens=special_tokens, unk_token="<unk>"
)
tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer)
```

Un argument foarte important care nu trebuie uitat pentru `UnigramTrainer` este `unk_token`. Putem trece și alte argumente specifice algoritmului Unigram, cum ar fi `shrinking_factor` pentru fiecare pas în care eliminăm tokeni (valoarea implicită este 0,75) sau `max_piece_length` pentru a specifica lungimea maximă a unui token dat (valoarea implicită este 16).

Acest tokenizer poate fi antrenat și pe fișiere text:

```python
tokenizer.model = models.Unigram()
tokenizer.train(["wikitext-2.txt"], trainer=trainer)
```

Să aruncăm o privire la tokenizarea unui exemplu de text:

```python
encoding = tokenizer.encode("Let's test this tokenizer.")
print(encoding.tokens)
```

```python out
['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.']
```

O particularitate a XLNet este că pune tokenul `<cls>` la sfârșitul propoziției, cu un ID de tip 2 (pentru a-l distinge de ceilalți tokeni). Ca urmare, este făcut padding la stânga. Putem trata toți tokenii speciali și ID-urile de tip ale tokenilor cu un template, ca în cazul BERT, dar mai întâi trebuie să obținem ID-urile tokenilor `<cls>` și `<sep>`:

```python
cls_token_id = tokenizer.token_to_id("<cls>")
sep_token_id = tokenizer.token_to_id("<sep>")
print(cls_token_id, sep_token_id)
```

```python out
0 1
```

Templateul arată astfel:

```python
tokenizer.post_processor = processors.TemplateProcessing(
    single="$A:0 <sep>:0 <cls>:2",
    pair="$A:0 <sep>:0 $B:1 <sep>:1 <cls>:2",
    special_tokens=[("<sep>", sep_token_id), ("<cls>", cls_token_id)],
)
```

Și putem testa că funcționează prin codificarea unei perechi de propoziții:

```python
encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!")
print(encoding.tokens)
print(encoding.type_ids)
```

```python out
['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '<sep>', '▁', 'on', '▁', 'a', '▁pair', 
  '▁of', '▁sentence', 's', '!', '<sep>', '<cls>']
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]
```

În cele din urmă, adăugăm un decoder `Metaspace`:

```python
tokenizer.decoder = decoders.Metaspace()
```

și am terminat cu acest tokenizer! Putem salva tokenizerul ca înainte și îl putem încorpora într-un `PreTrainedTokenizerFast` sau `XLNetTokenizerFast` dacă dorim să îl folosim în 🤗 Transformers. Un lucru de reținut atunci când se utilizează `PreTrainedTokenizerFast` este că, pe lângă tokenii speciali, trebuie să spunem bibliotecii 🤗 Transformers să facă padding la stânga:

```python
from transformers import PreTrainedTokenizerFast

wrapped_tokenizer = PreTrainedTokenizerFast(
    tokenizer_object=tokenizer,
    bos_token="<s>",
    eos_token="</s>",
    unk_token="<unk>",
    pad_token="<pad>",
    cls_token="<cls>",
    sep_token="<sep>",
    mask_token="<mask>",
    padding_side="left",
)
```

Sau alternativ:

```python
from transformers import XLNetTokenizerFast

wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer)
```

Acum că ați văzut cum sunt utilizate diferitele blocuri de construcție pentru a construi tokenizeri existenți, ar trebui să puteți scrie orice tokenizer doriți cu biblioteca 🤗 Tokenizers și să îl puteți utiliza în 🤗 Transformers.
